home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Audio-DSP / NU / Source / InstanceManager.m < prev    next >
Encoding:
Text File  |  1992-12-23  |  21.7 KB  |  754 lines

  1. #import "InstanceManager.h"
  2. #import "GlyphView.h"
  3. #import <appkit/Application.h>
  4. #import <appkit/Text.h>
  5. #import <appkit/Panel.h>
  6. #import <appkit/NXBrowser.h>
  7. #import <appkit/NXBrowserCell.h>
  8. #import <appkit/NXSplitView.h>
  9. #import <appkit/Matrix.h>
  10. #import <appkit/NXImage.h>
  11. #import <appkit/NXCursor.h>
  12. #import <objc/objc-class.h>
  13. #import <objc/List.h>
  14. #import <dpsclient/psops.h>
  15. #import <dpsclient/wraps.h>
  16. #import <stdlib.h>
  17. #import <strings.h>
  18. #import <libc.h>
  19. #import "NuString.h"
  20. #import "MenuManager.h"
  21. #import "NuWraps.h"
  22. #import <appkit/nextstd.h>
  23.  
  24. extern char bigBuf[] ;
  25. static char lastPath[256] ; // last path in the browser
  26. NXRect boundsRect ; // used to remember visible boundary
  27.   // of glyphView during resize operations
  28. union _alltypes // data types we can display in insVarBrowser
  29. { NXRect NXRectType ;
  30.   NXPoint NXPointType ;
  31.   NXSize NXSizeType ;
  32.   double doubleType ;
  33.   float floatType ;
  34.   int intType ;
  35.   unsigned unsignedIntType ;
  36.   id idType ;
  37.   short shortType ;
  38.   unsigned short unsignedShortType ;
  39.   char * stringType ;
  40.   char charType ;
  41. } *allTypes ;
  42.  
  43. // cursor used when resizing
  44. id sizerCursor = nil ;
  45.  
  46. // knobs for resizing, using code from Draw and then
  47. // optimized
  48. static int KNOB_WIDTH = 5.0;
  49. static int KNOB_HEIGHT = 5.0;
  50. static NXRect blackRectList[8] ;
  51. static NXRect dkgrayRectList[8];
  52.  
  53.  
  54. static void drawKnobs(const NXRect *rect)
  55. {  NXRect knob ;
  56.    NXRect *rectList ;
  57.    NXCoord dx, dy;
  58.    BOOL oddx, oddy;
  59.    int i = 0  ;
  60.    knob = *rect;
  61.    rectList = blackRectList ; 
  62.    while(1) // do blackRects first, then dkgrayRects
  63.    { dx = knob.size.width / 2.0;
  64.      dy = knob.size.height / 2.0;
  65.      oddx = (floor(dx) != dx);
  66.      oddy = (floor(dy) != dy);
  67.      knob.size.width = KNOB_WIDTH;
  68.      knob.size.height = KNOB_HEIGHT;
  69.      knob.origin.x -= ((KNOB_WIDTH - 1.0) / 2.0);
  70.      knob.origin.y -= ((KNOB_HEIGHT - 1.0) / 2.0);
  71.     // knobs are drawn clockwise from bottom left
  72.    
  73.                                                          rectList[i++] = knob ;
  74.      knob.origin.y += dy; if(oddy) knob.origin.y -= 0.5; rectList[i++] = knob ;
  75.      knob.origin.y += dy; if(oddy) knob.origin.y += 0.5; rectList[i++] = knob ;
  76.      knob.origin.x += dx; if(oddx) knob.origin.x -= 0.5; rectList[i++] = knob ;  
  77.      knob.origin.x += dx; if(oddx) knob.origin.x += 0.5; rectList[i++] = knob ;
  78.      knob.origin.y -= dy; if(oddy) knob.origin.y -= 0.5; rectList[i++] = knob ;
  79.      knob.origin.y -= dy; if(oddy) knob.origin.y += 0.5; rectList[i++] = knob ;
  80.      knob.origin.x -= dx; if(oddx) knob.origin.x += 0.5; rectList[i++] = knob ;
  81.      if(rectList == dkgrayRectList) // then we're done
  82.        break ;
  83.      // set up for the dkgray iteration
  84.      rectList = dkgrayRectList ;
  85.      knob = *rect ; i = 0 ;
  86.      knob.origin.x -= 1.0; knob.origin.y += 1.0;
  87.   }
  88.   PSsetgray(NX_DKGRAY);
  89.   PSsetlinewidth(0.0) ;
  90.   NXFrameRectWithWidth(rect,0.0) ;
  91.   PSsetgray(NX_BLACK);
  92.   NXRectFillList(blackRectList, 8);
  93.   PSsetgray(NX_DKGRAY);
  94.   NXRectFillList(dkgrayRectList, 8);
  95. }
  96.  
  97. static void drawKnobsAux(llx,lly, urx, ury)
  98. float llx,lly,urx,ury ;
  99. { // convert to an NXRect, then call drawKnobs
  100.   NXRect aRect = {{llx,lly},{urx-llx,ury-lly}} ;
  101.   return drawKnobs(&aRect) ;
  102. }
  103.  
  104. @implementation InstanceManager:WorkspaceManager
  105. { // ivars for the widgets
  106.   id originX, originY, originLink ;
  107.   id scaleWidth, scaleHeight, scaleLink ;
  108.   id resizeType ;
  109.   // ivars for the browser and text
  110.   id splitView ;
  111.   id insVarBrowser ;
  112.   id classList, insVarList ;
  113.   // hang on to targetGlyph and GlyphView id's
  114.   Glyph *targetGlyph ;
  115.   GlyphView *glyphView ;
  116.   // resizing rectangle
  117.   float llx, lly, urx, ury ;
  118.   float llxm, llym, urxm, urym ;
  119.   // ivar for knobbies
  120.   BOOL sizerRunning ; // true iff the knobbies are on
  121.   NXRect targetFrame ; // frame of targetGlyph in glyphView coords
  122.   NXRect trackRect ; // tracking rectangle for knobbies in base coords
  123. }
  124.  
  125.  
  126.  
  127. + cursor ;
  128. { // returns the cursor to use during
  129.   // resize operations
  130.   static id cursor = nil ;
  131.   if(!cursor)
  132.   { id anImage ;
  133.     NXSize aSize = {16.0,16.0} ;
  134.     NXPoint hotSpot = {2.0,2.0} ;
  135.     anImage = [[NXImage alloc] initSize: &aSize] ;
  136.     [anImage lockFocus] ;
  137.     PSsendstring(
  138.    "0 setalpha "
  139.    "1 setgray "
  140.    "0 0 16 16 rectfill "
  141.    "1 setalpha "
  142.    "1 setgray "
  143.      "0 setgray "
  144.      "0 11 5 5 rectfill "
  145.      "stroke ") ;              
  146.     PScvx() ;
  147.     PSexec() ;
  148.     [anImage unlockFocus] ;
  149.     cursor = [[NXCursor alloc] initFromImage: anImage] ;
  150.     [cursor setHotSpot: &hotSpot] ;
  151.   }
  152.   return cursor ;
  153. }
  154.  
  155. - accept: sender ;
  156. { // change my state according to the vals
  157.   // in the text fields
  158.   NXPoint aPnt ;
  159.   double  mx, my ;
  160.   targetGlyph = [Nu targetGlyph] ;
  161.   if(!targetGlyph->flags.isRoot) // can't move rootGlyph
  162.   { aPnt.x = [[originX cell] floatValue] ;
  163.     aPnt.y = [[originY cell] floatValue] ;
  164.     [[glyphView rootGlyph] moveGlyph: targetGlyph
  165.       toPoint: &aPnt ofGlyph: [targetGlyph ancestor]] ;
  166.   }
  167.   aPnt.x = [[scaleWidth cell] floatValue] ;
  168.   aPnt.y = [[scaleHeight cell] floatValue] ;
  169.   mx = aPnt.x / targetGlyph->scale.width ;
  170.   my = aPnt.y / targetGlyph->scale.height ;
  171.   [[glyphView rootGlyph] resizeTargetBy: mx :my
  172.      pile: [resizeType selectedCol]] ;
  173.   return self ;
  174. }
  175.  
  176. - ancestor: sender ;
  177. { return
  178.     [self changeTargetTo: [targetGlyph ancestor]] ;
  179. }
  180.  
  181.  
  182.  
  183. - (int)browser:sender fillMatrix:matrix inColumn:(int)column ;
  184. { if(column == 0)
  185.   { // then this is the class column
  186.     return [classList count] ;
  187.   }
  188.   else // column == 1
  189.   { struct objc_ivar_list *aList ;
  190.     struct objc_class *aClass  ;
  191.     int i,knt ;
  192.     Ivar theVar ;
  193.     id theText ;
  194.     [insVarList freeObjects] ;
  195.     aClass = (struct objc_class *)  [classList objectAt:
  196.        [[insVarBrowser matrixInColumn: 0] selectedRow]] ;
  197.     aList = aClass->ivars ;
  198.     if(!aList) // no list at all when 0 ivars
  199.       return 0 ; 
  200.     knt = aList->ivar_count ;
  201.     for(i = 0 ; i < knt ; i++)
  202.     { theVar = &(aList->ivar_list[i]) ;
  203.       [insVarList addObject:
  204.         theText = [NuString new: theVar->ivar_type]] ;
  205.       [theText catString: " "] ;
  206.       [theText catString: theVar->ivar_name] ;
  207.     }
  208.     return knt ;
  209.   }
  210. }
  211.  
  212. - browser:sender loadCell:cell atRow:(int)row inColumn:(int)column ;
  213. { if(column == 0)
  214.   { [cell setStringValue: [[classList objectAt: row] name]] ;
  215.     [cell setLeaf: NO] ;
  216.   }
  217.   else // column == 1
  218.   { [cell setLeaf: YES] ;
  219.     [cell setStringValue: [[insVarList objectAt: row] cString]] ;
  220.   }
  221.   return self ;
  222. }
  223.  
  224. - changeTargetTo: (Glyph *) aGlyph ;
  225. { if(!aGlyph->flags.isTerminator)
  226.   { [aGlyph becomeTarget] ;
  227.     [self instance: aGlyph] ;
  228.   }
  229.   return self ;
  230. }
  231.  
  232. - clone: sender ;
  233. { // clone the target glyph, than plant it in the current
  234.   // target after moving it halfway across the and halfway
  235.   // up the current target.  Then make the clone the current
  236.   // target.
  237.   Glyph *aClone ;
  238.   aClone = [targetGlyph clone] ;
  239.   aClone->frame.origin.x = targetGlyph->frame.origin.x +
  240.     targetGlyph->frame.size.width / 2.0 ;
  241.   aClone->frame.origin.y = targetGlyph->frame.origin.y +
  242.       targetGlyph->frame.size.height / 2.0 ;
  243.   [aClone moveOriginTo: &aClone->frame.origin ofGlyph: targetGlyph->ancestor] ;
  244.   [aClone becomeTarget] ;
  245.   return self ;
  246. }
  247.  
  248. - delete: sender ;
  249. { return [targetGlyph die] ;
  250. }
  251.  
  252. - dOX: sender ;
  253. { id aCell = [originX cell] ;
  254.   [aCell setFloatValue: [aCell floatValue] - 1.0] ;
  255.   if([originLink state])
  256.     [originY setFloatValue: [originY floatValue] - 1.0] ;
  257.   [self accept: self] ;
  258.   return self ;
  259. }
  260.  
  261. - dOY: sender ;
  262. { id aCell = [originY cell] ;
  263.   [aCell setFloatValue: [aCell floatValue] - 1.0] ;
  264.   if([originLink state])
  265.     [originX setFloatValue: [originX floatValue] - 1.0] ;
  266.   [self accept: self] ;
  267.   return self ;
  268. }
  269.  
  270.  
  271. - dSW: sender ;
  272. { id aCell = [scaleWidth cell] ;
  273.   [aCell setFloatValue: [aCell floatValue] - 1.0] ;
  274.   if([scaleLink state])
  275.    [[scaleHeight cell] setFloatValue: [aCell floatValue]] ;
  276.   [self accept: self] ;
  277.   return self ;
  278. }
  279.  
  280. - dSH: sender ;
  281. { id aCell = [scaleHeight cell] ;
  282.   [aCell  setFloatValue: [aCell floatValue] - 1.0] ;
  283.   if([scaleLink state])
  284.    [[scaleWidth cell] setFloatValue: [aCell floatValue]] ;
  285.   [self accept: self] ;
  286.   return self ;
  287. }
  288.  
  289.  
  290. - instance: aGlyph ;
  291. { // setup the insVarBrowser to browse this
  292.   // Glyph
  293.   struct objc_class *aClass, *glyphSuperClass ;
  294.   if(!aGlyph)
  295.   { return nil ;
  296.   }
  297.   targetGlyph = aGlyph ;
  298.   glyphView = [Nu glyphView] ;
  299.   [self setTitle: [targetGlyph name]] ;
  300.   // update the scale and origin
  301.   [[scaleWidth  cell] setFloatValue: targetGlyph->scale.width] ;
  302.   [[scaleHeight cell] setFloatValue: targetGlyph->scale.height] ;
  303.   [self setOrigin] ;
  304.  
  305.   [classList empty] ; // don't wanna free these guys!
  306.   [insVarList freeObjects] ;
  307.   // make class list for this class
  308.   aClass = (struct objc_class *) [targetGlyph class] ;
  309.   glyphSuperClass = 
  310.     (struct objc_class *) [objc_getClass("Glyph") superClass]  ;
  311.   while(aClass != glyphSuperClass)
  312.   { // walk the inheritance chain
  313.     [classList addObject: (id) aClass] ;
  314.     aClass = aClass->super_class ;
  315.   }
  316.   [insVarBrowser loadColumnZero] ;
  317.   [insVarBrowser setPath: lastPath] ;
  318.   [self showValue: self] ;
  319.   return self ;
  320. }
  321.  
  322. - iOX: sender ;
  323. { id aCell = [originX cell] ;
  324.   [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  325.   if([originLink state])
  326.     [originY setFloatValue: [originY floatValue] + 1.0] ;
  327.   [self accept: self] ;
  328.   return self ;
  329. }
  330.  
  331. - iOY: sender ;
  332. { id aCell = [originY cell] ;
  333.   [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  334.   if([originLink state])
  335.     [originX setFloatValue: [originX floatValue] + 1.0] ;
  336.   [self accept: self] ;
  337.   return self ;
  338. }
  339.  
  340. - init ;
  341. { // set the browser to two columns only
  342.   [insVarBrowser setAutoresizeSubviews: YES] ;
  343.   [insVarBrowser setMinColumnWidth: 1.0] ;
  344.   [insVarBrowser setMaxVisibleColumns: 2] ;
  345.   // assemble the pieces we get from the nib
  346.   [insVarBrowser useScrollButtons: YES] ;
  347.   [splitView addSubview: [insVarBrowser removeFromSuperview]] ;
  348.   [splitView addSubview: [[[textView superview] superview]
  349.       removeFromSuperview]] ;
  350.   // make sure we are not monofont
  351.   [textView setMonoFont: NO] ; 
  352.   isRTF =  NO ;
  353.   [self setMiniwindowIcon: "cmIcon.tiff"] ;
  354.   // become the textView's delegate so we'll get a textDidGetKeys:isEmpty:
  355.   // whenever the text is edited
  356.   [textView setDelegate: self] ;
  357.   // make lastPath empty
  358.   lastPath[0] = '\0' ;
  359.   // create Storage for class names and
  360.   // Ivar names
  361.   classList = [List new] ;
  362.   insVarList = [List new] ;
  363.   return self ;
  364. }
  365.  
  366.  
  367. - is: sender ;
  368. { return
  369.     [self changeTargetTo: [targetGlyph is]] ;
  370. }
  371.  
  372.  
  373. - iSW: sender ;
  374. { id aCell = [scaleWidth cell] ;
  375.   [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  376.   if([scaleLink state])
  377.    [[scaleHeight cell] setFloatValue: [aCell floatValue]] ;
  378.   [self accept: self] ;
  379.   return self ;
  380. }
  381.  
  382. - iSH: sender ;
  383. { id aCell = [scaleHeight cell] ;
  384.   [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  385.   if([scaleLink state])
  386.    [[scaleWidth cell] setFloatValue: [aCell floatValue]] ;
  387.   [self accept: self] ;
  388.   return self ;
  389. }
  390.  
  391. NXPoint eventOrigin ; // remember where event began
  392. BOOL mouseDragged  ; // set to YES if a mouseDragged is received
  393. // mouse messages are relayed from
  394. // glyphView during resizing operations
  395.  
  396. - mouseDown: (NXEvent *) anEvent ;
  397. { int i ;
  398.   mouseDragged = NO ;
  399.   // make sure glyphView and instance are up-to-date
  400.   glyphView = [Nu glyphView] ;
  401.   [self instance: [Nu targetGlyph]] ;
  402.   // set llx,lly,urx,ury tp target's frame
  403.   targetFrame = targetGlyph->frame ;
  404.   [[targetGlyph ancestor] convertToRootGlyph: &targetFrame.origin] ;
  405.   llx = targetFrame.origin.x ;
  406.   lly = targetFrame.origin.y ;
  407.   urx = llx + targetFrame.size.width ;
  408.   ury = lly + targetFrame.size.height ;
  409.   // draw the knobs
  410.   [glyphView lockFocus] ; // unlocked in mouseUp:
  411.   PSnewinstance() ;
  412.   PSsetinstance(YES) ;
  413.   drawKnobsAux(llx,lly,urx,ury) ;
  414.   PSsetinstance(NO) ;
  415.   // remember the event's origin
  416.   eventOrigin = anEvent->location ;
  417.   [glyphView convertPoint: &eventOrigin fromView: nil] ;
  418.   // find if cursor is in a knobbie
  419.   for(i = 0 ; i < 8 ; i++) 
  420.   { if(NXPointInRect(
  421.        (const NXPoint *) &eventOrigin,(const NXRect *) &(blackRectList[i])))
  422.         break ;
  423.   }
  424.   // (if i == 8, then not in knobbies)
  425.   // figure out the multipliers used to compute the next
  426.   // position of the knobbies
  427.   llxm = llym = urxm = urym = 0.0 ;
  428.   if(i <= 2)
  429.     llxm = 1.0 ;
  430.   else if((4 <= i) &&  (i <= 6))
  431.     urxm = 1.0 ;
  432.   if((i == 0) || (i == 7) || (i == 6))
  433.     llym = 1.0 ; 
  434.   else if((i == 2) || (i == 3) || (i == 4))
  435.     urym = 1.0 ;
  436.   return self ;
  437. }
  438.  
  439.  
  440. - mouseDragged: (NXEvent *) anEvent ;
  441. { float dx, dy, temp ;
  442.   float prevllx = llx, prevlly = lly,
  443.         prevurx = urx, prevury = ury ;
  444.   mouseDragged = YES ;
  445.   [glyphView convertPoint: &anEvent->location fromView: nil] ;
  446.   dx = anEvent->location.x - eventOrigin.x ;
  447.   dy = anEvent->location.y - eventOrigin.y ;
  448.   eventOrigin = anEvent->location ;
  449.   if(llxm + llym + urxm + urym == 2.0) // moving 2 coords?
  450.   { // If so, must maintain the glyph's aspect ratio.
  451.     // Are we pulling from upper left or lower right?
  452.     BOOL upperLeftOrLowerRight = (llxm && urym) || (urxm && llym) ;
  453.     // compute current aspect ratio (we must maintain this)
  454.     float aspect = (urx - llx) / (ury - lly) ;
  455.     // Find which coord moved the most, then recompute the other
  456.     // coord using this coord andthe aspect ratio
  457.     // compute dy from thes new dx and the aspect ratio
  458.     if(abs(dx) > abs(dy)) // more x motion
  459.     {  dy = dx / aspect ; 
  460.        if(upperLeftOrLowerRight)
  461.          dy *= -1.0 ;
  462.     }
  463.     else
  464.     { dx = dy * aspect ;
  465.        if(upperLeftOrLowerRight)
  466.          dx *= -1.0 ;
  467.     }
  468.   }
  469.   // apply dx and dy to the resizing rectangle 
  470.   temp = dx * llxm ;
  471.   if((llx + temp) >= urx) // don't allow!
  472.     temp = 0.0 ;
  473.   else
  474.     llx += temp ;
  475.   [[originX cell] setFloatValue: [originX floatValue] + temp] ;
  476.   temp = dy * llym ;
  477.   if((lly + temp) >= ury) // don't allow!
  478.     temp = 0.0 ;
  479.   else
  480.     lly += temp  ;
  481.   [[originY cell] setFloatValue: [originY floatValue] + temp] ;
  482.   urx += dx * urxm ;
  483.   if(urx <= llx) // don't allow this to happen!
  484.     urx = llx + 1.0 ;
  485.   [[scaleWidth cell] setFloatValue: [scaleWidth floatValue] *
  486.      (urx - llx) / (prevurx - prevllx)] ;
  487.   ury += dy * urym ;
  488.   if(ury <= lly) // don't allow this!
  489.     ury = lly + 1.0 ;
  490.   [[scaleHeight cell] setFloatValue: [scaleHeight floatValue] *
  491.      (ury - lly) / (prevury - prevlly)] ;
  492.   PSnewinstance() ;
  493.   PSsetinstance(YES) ;
  494.   drawKnobsAux(llx,lly,urx,ury) ;
  495.   PSsetinstance(NO) ;
  496.   return self ;
  497. }
  498.  
  499. - mouseUp: (NXEvent *) anEvent ;
  500. { if(mouseDragged) // if the target was resized...
  501.     [self accept: self] ;
  502.   // need to redraw the knobs here, otherwise
  503.   // they end up half obscured
  504.   PSnewinstance() ;
  505.   PSsetinstance(YES) ;
  506.   drawKnobsAux(llx,lly,urx,ury) ;
  507.   PSsetinstance(NO) ;
  508.   [glyphView unlockFocus] ;
  509.   return self ;
  510. }
  511.  
  512. - precursor: sender ;
  513. { return
  514.     [self changeTargetTo: [targetGlyph  precursor]] ;
  515. }
  516.  
  517.  
  518. - setOrigin ;
  519. { // set the origin values 
  520.   [[originX cell] setFloatValue: targetGlyph->frame.origin.x] ;
  521.   [[originY cell] setFloatValue: targetGlyph->frame.origin.y] ;
  522.   return self ;
  523. }
  524.  
  525.  
  526. - setValue: sender ;
  527. { // set the value of the selected ivar. The
  528.   // code here is symmetrical with the code
  529.   // for showValue: 
  530.   NXStream *aStream ;
  531.   struct objc_ivar_list *aList ;
  532.   struct objc_class *aClass  ;
  533.   Ivar theVar ;
  534.   int i,j, textLen ;
  535.   if(![self isDocEdited])
  536.   // only set the value if the user actually typed something
  537.   // in the textView
  538.     return self ;
  539.   i = [[insVarBrowser matrixInColumn: 1] selectedRow] ;
  540.   j = [[insVarBrowser matrixInColumn: 0] selectedRow] ;
  541.   if(i < 0 || j < 0) 
  542.      return nil ;
  543.   aClass = (struct objc_class *)  [classList objectAt: j] ;
  544.   aList = aClass->ivars ;
  545.   theVar = &(aList->ivar_list[i]) ;
  546.   allTypes =   &(((char *)targetGlyph)[theVar->ivar_offset]) ;
  547.   aStream = [textView stream] ;
  548.   // make sure we are null terminated
  549.   switch(theVar->ivar_type[0])
  550.   { case 'd': // double
  551.       NXScanf(aStream,"%lf\n",&allTypes->doubleType) ;
  552.       break ;
  553.     case 'f': // float
  554.       NXScanf(aStream,"%f\n",&allTypes->floatType) ;
  555.       break ;
  556.     case 'i': // integer
  557.       NXScanf(aStream,"%d\n",&allTypes->intType) ;
  558.       break ;
  559.     case 'I': // unsigned integer
  560.       NXScanf(aStream,"%u\n",&allTypes->unsignedIntType) ;
  561.       break ;
  562.     case 's': // short
  563.       NXScanf(aStream,"%hd\n",&allTypes->shortType) ;
  564.       break ;
  565.     case 'S': // unsigned short
  566.       NXScanf(aStream,"%hu\n",&allTypes->unsignedShortType) ;
  567.       break ;
  568.     case '{': // a struct, but what kind of struct?
  569.       if(!strncmp(theVar->ivar_type,"{_NXPoint}",10)) 
  570.         NXScanf(aStream,"%f@%f",
  571.      &allTypes->NXPointType.x, &allTypes->NXPointType.y) ;
  572.       else if(!strncmp(theVar->ivar_type,"{_NXSize}",9)) 
  573.         NXScanf(aStream,"%f@%f",
  574.      &allTypes->NXSizeType.width, &allTypes->NXSizeType.height) ;
  575.       else if(!strncmp(theVar->ivar_type,"{_NXRect}",9))
  576.          NXScanf(aStream,"%f@%f,%f@%f\n",
  577.            &allTypes->NXRectType.origin.x,&allTypes->NXRectType.origin.y,
  578.       &allTypes->NXRectType.size.width, &allTypes->NXRectType.size.width) ;
  579.       else
  580.       {  sprintf(bigBuf,"Cannot set value for type %s",
  581.            theVar->ivar_type) ;
  582.     [textView setText: bigBuf] ;
  583.     NXPing() ;
  584.          usleep(1000000) ;
  585.       }
  586.       break ;
  587.       case 'c': // character type
  588.       case 'C': // unsigned char ... enter in octal
  589.     { int tmp ;
  590.            NXScanf(aStream,"\\%o",&tmp) ;
  591.       allTypes->charType = tmp & 0x00ff ;
  592.     }
  593.     break ;
  594.       case '*': // string type
  595.          // free old string, allocate new one
  596.          free(allTypes->stringType) ;
  597.          textLen = [textView textLength] + 1 ;
  598.          allTypes->stringType = (char *) malloc(textLen) ;
  599.     [textView getSubstring: allTypes->stringType
  600.              start: 0 length: textLen] ;
  601.     break ;    
  602.        case '@': // id type
  603.          { // look for "Location: <path string> 
  604.       id aGlyph ;
  605.       char path[256] ;
  606.       NXScanf(aStream,"Location:%s\n",path) ;
  607.       aGlyph = [targetGlyph glyphAtPath: path] ;
  608.       if(!aGlyph)
  609.       { sprintf(bigBuf,"Error. No glyph at path: %s",path) ;
  610.         [textView setText: bigBuf] ;
  611.         NXPing() ;
  612.              usleep(1000000) ;
  613.            }
  614.        else
  615.         allTypes->idType = aGlyph ;
  616.     }
  617.          break ;
  618.       default:
  619.     sprintf(bigBuf,"Cannot set value for type %s",
  620.            theVar->ivar_type) ;
  621.     [textView setText: bigBuf] ;
  622.     NXPing() ;
  623.          usleep(1000000) ;
  624.     break ;
  625.   }
  626.   return [self showValue: self] ;
  627. }
  628.  
  629. - showValue: sender ;
  630. { // show the value of the selected ivar
  631.   struct objc_ivar_list *aList ;
  632.   struct objc_class *aClass  ;
  633.   Ivar theVar ;
  634.   int i,j ;
  635.   i = [[insVarBrowser matrixInColumn: 1] selectedRow] ;
  636.   j = [[insVarBrowser matrixInColumn: 0] selectedRow] ;
  637.   if(i < 0 || j < 0)
  638.   { [textView setText: ""] ;
  639.     return nil ;
  640.   }
  641.   // set default path to the last path, if possible
  642.   [insVarBrowser getPath: lastPath toColumn: 2] ;
  643.   aClass = (struct objc_class *)  [classList objectAt: j] ;
  644.   aList = aClass->ivars ;
  645.   theVar = &(aList->ivar_list[i]) ;
  646.   allTypes =   &(((char *)targetGlyph)[theVar->ivar_offset]) ;
  647.   bigBuf[0] = '\0' ;
  648.   switch(theVar->ivar_type[0])
  649.   { case 'd': // double
  650.       sprintf(bigBuf,"%lf\n",allTypes->doubleType) ;
  651.       break ;
  652.     case 'f': // float
  653.       sprintf(bigBuf,"%f\n",allTypes->floatType) ;
  654.       break ;
  655.     case 'i': // integer
  656.       sprintf(bigBuf,"%d\n",allTypes->intType) ;
  657.       break ;
  658.     case 'I': // unsigned integer
  659.       sprintf(bigBuf,"%u\n",allTypes->unsignedIntType) ;
  660.       break ;
  661.     case 's': // short
  662.       sprintf(bigBuf,"%hd\n",allTypes->shortType) ;
  663.       break ;
  664.     case 'S': // unsigned short
  665.       sprintf(bigBuf,"%hu\n",allTypes->unsignedShortType) ;
  666.       break ;
  667.     case '{': // a struct, but what kind of struct?
  668.       if(!strncmp(theVar->ivar_type,"{_NXPoint}",10)) 
  669.         sprintf(bigBuf,"%f@%f",
  670.      allTypes->NXPointType.x, allTypes->NXPointType.y) ;
  671.       else if(!strncmp(theVar->ivar_type,"{_NXSize}",9)) 
  672.         sprintf(bigBuf,"%f@%f",
  673.      allTypes->NXSizeType.width, (allTypes->NXSizeType).height) ;
  674.       else if(!strncmp(theVar->ivar_type,"{_NXRect}",9))
  675.          sprintf(bigBuf,"%f@%f,%f@%f\n",
  676.            allTypes->NXRectType.origin.x,allTypes->NXRectType.origin.y,
  677.       allTypes->NXRectType.size.width, allTypes->NXRectType.size.width) ;
  678.       else
  679.     sprintf(bigBuf,"Cannot display value for type %s",
  680.            theVar->ivar_type) ;
  681.       break ;
  682.       case 'c': // character type
  683.     sprintf(bigBuf,"\\%o\n0x%x\n%d\n'%c'\n",allTypes->charType & 0x00ff,
  684.            allTypes->charType & 0x00ff,
  685.            allTypes->charType,allTypes->charType) ;
  686.     break ;
  687.       case 'C': // unsigned char 
  688.     sprintf(bigBuf,"\\%o\n0x%x\n%u\n'%c'\n",allTypes->charType & 0x00ff,
  689.            allTypes->charType & 0x00ff,
  690.            allTypes->charType,allTypes->charType) ;
  691.     break ;
  692.       case '*': // string type
  693.     sprintf(bigBuf,"%s\n",allTypes->stringType) ;
  694.     break ;    
  695.        case '@': // id type
  696.     sprintf(bigBuf,"Location: 0x%x\nInstance name: %s\nClassName:%s\n",
  697.           allTypes->idType,
  698.      [allTypes->idType name],
  699.           [[allTypes->idType class] name]) ;
  700.       break ;
  701.       default:
  702.     sprintf(bigBuf,"Cannot display value for type %s",
  703.            theVar->ivar_type) ;
  704.         break ;
  705.   }
  706.   [textView setText: bigBuf] ;
  707.   NXPing() ;
  708.   [self setDocEdited: NO] ;
  709.   return self ;
  710. }
  711.  
  712. - startSizer: sender ;
  713. { // start up for resizing the target glyph
  714.   glyphView = [Nu glyphView] ; // get current glyphView and target glyph
  715.   [self instance: [Nu targetGlyph]] ;
  716.   targetFrame = targetGlyph->frame ;
  717.   [[targetGlyph ancestor] convertToRootGlyph: &targetFrame.origin] ;
  718.   // the resizing rectangle is described using 4 floats...
  719.   llx = targetFrame.origin.x ;
  720.   lly = targetFrame.origin.y ;
  721.   urx = llx + targetFrame.size.width ;
  722.   ury = lly + targetFrame.size.height ;
  723.   // draw it
  724.   [glyphView lockFocus] ;
  725.   PSnewinstance() ;
  726.   PSsetinstance(YES) ;
  727.   drawKnobsAux(llx,lly,urx,ury) ; 
  728.   PSsetinstance(NO) ;
  729.   [glyphView unlockFocus] ;
  730.   return self ;
  731. }
  732.  
  733. - stopSizer: sender ;
  734. { PSnewinstance() ; // clear instance drawing
  735.   return self ;
  736. }
  737.  
  738. - targetGlyph ;
  739. { return targetGlyph ;
  740. }
  741.  
  742. - textDidGetKeys:(id) theText isEmpty: (BOOL) flag ;
  743. { if(![self isDocEdited])
  744.    [self setDocEdited: YES] ;
  745. }
  746.  
  747. - then: sender ;
  748. { return
  749.     [self changeTargetTo: [targetGlyph  then]] ;
  750. }
  751.  
  752.  
  753. @end
  754.